﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
using Biblioteca.Models;
using System.Web.Configuration;

public class MyMembershipProvider: MembershipProvider
{
    #region Class Variables

    private int newPasswordLength = 6;
    private string connectionString;
    private string applicationName;
    private bool enablePasswordReset;
    private bool enablePasswordRetrieval;
    private bool requiresQuestionAndAnswer;
    private bool requiresUniqueEmail;
    private int maxInvalidPasswordAttempts;
    private int passwordAttemptWindow;
    private MembershipPasswordFormat passwordFormat;
    private int minRequiredNonAlphanumericCharacters;
    private int minRequiredPasswordLength;
    private string passwordStrengthRegularExpression;
    private MachineKeySection machineKey; //Used when determining encryption key values.

    #endregion

    #region Properties

    public override string ApplicationName
    {
        get
        {
            return applicationName;
        }
        set
        {
            applicationName = value;
        }
    }

    public override bool EnablePasswordReset
    {
        get
        {
            return enablePasswordReset;
        }
    }

    public override bool EnablePasswordRetrieval
    {
        get
        {
            return enablePasswordRetrieval;
        }
    }

    public override bool RequiresQuestionAndAnswer
    {
        get
        {
            return requiresQuestionAndAnswer;
        }
    }

    public override bool RequiresUniqueEmail
    {
        get
        {
            return requiresUniqueEmail;
        }
    }

    public override int MaxInvalidPasswordAttempts
    {
        get
        {
            return maxInvalidPasswordAttempts;
        }
    }

    public override int PasswordAttemptWindow
    {
        get
        {
            return passwordAttemptWindow;
        }
    }

    public override MembershipPasswordFormat PasswordFormat
    {
        get
        {
            return passwordFormat;
        }
    }

    public override int MinRequiredNonAlphanumericCharacters
    {
        get
        {
            return minRequiredNonAlphanumericCharacters;
        }
    }

    public override int MinRequiredPasswordLength
    {
        get
        {
            return minRequiredPasswordLength;
        }
    }

    public override string PasswordStrengthRegularExpression
    {
        get
        {
            return passwordStrengthRegularExpression;
        }
    }

    #endregion

    #region No Implementados
        
    public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer)
    {
        throw new NotImplementedException();
    }

    public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
    {
        throw new NotImplementedException();
    }

    public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
    {
        throw new NotImplementedException();
    }

    public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
    {
        throw new NotImplementedException();
    }

    public override int GetNumberOfUsersOnline()
    {
        throw new NotImplementedException();
    }

    public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
    {
        throw new NotImplementedException();
    }

    public override string GetUserNameByEmail(string email)
    {
        throw new NotImplementedException();
    }

    public override string ResetPassword(string username, string answer)
    {
        throw new NotImplementedException();
    }

    public override bool UnlockUser(string userName)
    {
        throw new NotImplementedException();
    }

    #endregion

    #region Implementados

    public override bool ChangePassword(string username, string oldPassword, string newPassword)
    {
        if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(oldPassword) || string.IsNullOrWhiteSpace(newPassword)) return false;

        if (oldPassword == newPassword) return false;

     //   CustomMembershipUser user = GetUser(username);
       // if (user == null) return false;

        //Obtiene una cuenta activada con dado username
        BibliotecaStore db = new BibliotecaStore();
        Cuenta cta = (from u in db.Cuentas join p in db.CuentaUsuarios on u.IdCuenta equals p.Cuenta
                       where u.Usuario == username && p.Activada == 1
                       select u).FirstOrDefault();

        if (string.IsNullOrWhiteSpace(cta.Password)) return false;

        //Setea el nuevo password
        cta.Password = EncodePassword(newPassword);

        db.SaveChanges();

        return true;
    }

    public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
    {

        //Validacion de password... 
        ValidatePasswordEventArgs args = new ValidatePasswordEventArgs(username, password, true);

        OnValidatingPassword(args);

        if (args.Cancel)
        {
            status = MembershipCreateStatus.InvalidPassword;
            return null;
        }

        //Validacion email unico
        if ((RequiresUniqueEmail && (GetUserNameByEmail(email) != String.Empty)))
        {
            status = MembershipCreateStatus.DuplicateEmail;
            return null;
        }

        //Chequea si ya existe ese nombre de usuario en Cuentas
        MembershipUser membershipUser = GetUser(username, false);
        if (membershipUser == null)
        {
            try
            {
                using (BibliotecaStore _db = new BibliotecaStore())
                {
                    Cuenta cta = new Cuenta();
                  
                    cta.Usuario = username;
                    cta.Password = EncodePassword(password);

                    _db.Cuentas.AddObject(cta);

                    _db.SaveChanges();

                    status = MembershipCreateStatus.Success;

                    return GetUser(username, false);
                }

            }
            catch
            {
                status = MembershipCreateStatus.ProviderError;
            }
        }
        else
        {
            status = MembershipCreateStatus.DuplicateUserName;
        }

        return null;
    }

    public override bool DeleteUser(string username, bool deleteAllRelatedData)
    {
        bool exito = false;

        using (BibliotecaStore _db = new BibliotecaStore())
        {
            try
            {
                Cuenta user = (from u in _db.Cuentas
                             where u.Usuario == username
                             select u).FirstOrDefault();

                if (user != null)
                {
                    _db.Cuentas.DeleteObject(user);

                    _db.SaveChanges();

                    exito = true;
                }
            }
            catch
            {
                exito = false;
            }
        }

        return exito;
    }

    public override MembershipUser GetUser(string username, bool userIsOnline)
    {
        MembershipUser membershipUser = null;
        using (BibliotecaStore _db = new BibliotecaStore())
        {
            try
            {
                Cuenta user = (from u in _db.Cuentas join p in _db.CuentaUsuarios on u.IdCuenta equals p.Cuenta
                             where u.Usuario == username && p.Activada == 1
                             select u)
                             .FirstOrDefault();

                if (user != null)
                {
                    membershipUser = new MembershipUser(this.Name,
                        user.Usuario,
                        null,
                        null,
                        "",
                        "",
                        true,   //isApproved
                        false,  //isLockedOut
                        default(DateTime),
                        DateTime.Now,
                        DateTime.Now,
                        default(DateTime),
                        default(DateTime));
                }
            }
            catch
            {
            }
        }

        return membershipUser;
    }

    public override string GetPassword(string username, string answer)
    {
        using (BibliotecaStore _db = new BibliotecaStore())
        {
            try
            {
                var pass = (from p in _db.Cuentas
                            where p.Usuario == username
                            select p.Password).FirstOrDefault();
                if (!string.IsNullOrWhiteSpace(pass))
                    return UnEncodePassword(pass);
            }
            catch { }
        }
        return null;
    }

    public bool cambiarEstadoActivacion(string username)
    {
        using (BibliotecaStore db = new BibliotecaStore())
        {
            CuentaUsuario cta_us = (from u in db.Cuentas
                                    join p in db.CuentaUsuarios on u.IdCuenta equals p.Cuenta
                                    where u.Usuario == username
                                    select p).FirstOrDefault();
           
            if (cta_us == null)
            {
                //No existe una cuenta con ese username?
                return false;
            }

            //Cambia el estado de activacion
            if (cta_us.Activada == 0)
                cta_us.Activada = 1;
            else
                cta_us.Activada = 0;

            db.SaveChanges();
        }

        return true;
    }

    public override void UpdateUser(MembershipUser user)
    {
        throw new NotImplementedException();
    }

    public override bool ValidateUser(string username, string password)
    {
        bool valida = false;
        //using ( )
        BibliotecaStore db = new BibliotecaStore();
        {
                Cuenta cta = (from u in db.Cuentas
                              join p in db.CuentaUsuarios on u.IdCuenta equals p.Cuenta
                             where u.Usuario.Equals(username) &&
                                   u.Password.Equals(password)
                             select u).FirstOrDefault();

                if (cta == null)
                {
                    // Invalid user name or password
                    valida = false;
                    
                }
                else
                {
                    //Hace el join para determinar si la cuenta esta activa
                    CuentaUsuario activa = (from u in db.Cuentas
                                            join p in db.CuentaUsuarios on u.IdCuenta equals p.Cuenta
                                            where u.Usuario.Equals(username) &&
                                                  u.Password.Equals(password)
                                            select p).FirstOrDefault();

                    if (activa.Activada != 1)
                    {
                        valida = false;
                    }
                    else
                    {
                        valida = true;
                    }
                }
         }

        return valida;
    }

    #endregion

    #region Métodos Auxiliares

    /// <summary>
    /// Check the password format based upon the MembershipPasswordFormat.
    /// </summary>
    /// <param name="password">Password</param>
    /// <param name="dbpassword"></param>
    /// <returns></returns>
    /// <remarks></remarks>
    private bool CheckPassword(string password, string dbpassword)
    {
        string pass1 = password;
        string pass2 = dbpassword;

        switch (PasswordFormat)
        {
            case MembershipPasswordFormat.Encrypted:
                pass2 = UnEncodePassword(dbpassword);
                break;
            case MembershipPasswordFormat.Hashed:
                pass1 = EncodePassword(password);
                break;
            default:
                break;
        }

        if (pass1 == pass2)
        {
            return true;
        }

        return false;
    }

    /// <summary>
    /// UnEncode password.
    /// </summary>
    /// <param name="encodedPassword">Password.</param>
    /// <returns>Unencoded password.</returns>
    private string UnEncodePassword(string encodedPassword)
    {
        string password = encodedPassword;
        /*
        switch (PasswordFormat)
        {
            case MembershipPasswordFormat.Clear:
                break;
            case MembershipPasswordFormat.Encrypted:
                password =
                  Encoding.Unicode.GetString(DecryptPassword(Convert.FromBase64String(password)));
                break;
            case MembershipPasswordFormat.Hashed:
                //HMACSHA1 hash = new HMACSHA1();
                //hash.Key = HexToByte(machineKey.ValidationKey);
                //password = Convert.ToBase64String(hash.ComputeHash(Encoding.Unicode.GetBytes(password)));

                throw new ProviderException("Not implemented password format (HMACSHA1).");
            default:
                throw new ProviderException("Unsupported password format.");
        }*/

        return password;
    }

    /// <summary>
    /// Get config value.
    /// </summary>
    /// <param name="configValue"></param>
    /// <param name="defaultValue"></param>
    /// <returns></returns>
    private string GetConfigValue(string configValue, string defaultValue)
    {
        if (String.IsNullOrEmpty(configValue))
        {
            return defaultValue;
        }

        return configValue;
    }

    /// <summary>
    /// Encode password.
    /// </summary>
    /// <param name="password">Password.</param>
    /// <returns>Encoded password.</returns>
    private string EncodePassword(string password)
    {
        string encodedPassword = password;
        /*
        switch (PasswordFormat)
        {
            case MembershipPasswordFormat.Clear:
                break;
            case MembershipPasswordFormat.Encrypted:
                byte[] encryptedPass = EncryptPassword(Encoding.Unicode.GetBytes(password));
                encodedPassword = Convert.ToBase64String(encryptedPass);
                break;
            case MembershipPasswordFormat.Hashed:
                HMACSHA1 hash = new HMACSHA1();
                hash.Key = HexToByte(machineKey.ValidationKey);
                encodedPassword =
                  Convert.ToBase64String(hash.ComputeHash(Encoding.Unicode.GetBytes(password)));
                break;
            default:
                throw new ProviderException("Unsupported password format.");
        }*/

        return encodedPassword;
    }

    /// <summary>
    /// Converts a hexadecimal string to a byte array. Used to convert encryption key values from the configuration
    /// </summary>
    /// <param name="hexString"></param>
    /// <returns></returns>
    /// <remarks></remarks>
    private byte[] HexToByte(string hexString)
    {
        byte[] returnBytes = new byte[hexString.Length / 2];
        for (int i = 0; i < returnBytes.Length; i++)
            returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
        return returnBytes;
    }

    #endregion

}